package com.parallel.ofc;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.Map;
import java.util.concurrent.*;

/**
 * 任务处理工具
 * 1.创建线程池
 *  对于子任务，需要支持并发，如果每个并发都开一个线程，用完就关闭，对资源消耗太大，所以引入线程池：
 *
 */

public class TaskProcessUtil {
    /**
     * ExecutorService是Java提供的线程池，也就是说，每次我们需要使用线程的时候，可以通过ExecutorService获得线程。
     * 它可以有效控制最大并发线程数，提高系统资源的使用率，同时避免过多资源竞争，避免堵塞，同时提供定时执行、定期执行、单线程、并发数控制等功能，也不用使用TimerTask了。
     *
     * concurrentHashMap是一个支持高并发更新与查询的哈希表(基于HashMap)。
     * 在保证安全的前提下，进行检索不需要锁定。与hashtable不同，该类不依赖于synchronization去保证线程操作的安全。
     */

    // 每个任务，都有自己单独的线程池  相当于任务队列(任务池)
    private static Map<String, ExecutorService> executors = new ConcurrentHashMap<>();

    // 初始化一个线程池
    private static ExecutorService init(String poolName, int poolSize) {
        return new ThreadPoolExecutor(poolSize, poolSize,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(),
                new ThreadFactoryBuilder().setNameFormat("Pool-" + poolName).setDaemon(false).build(),
                new ThreadPoolExecutor.CallerRunsPolicy());
    }

    // 获取线程池
    public static ExecutorService getOrInitExecutors(String poolName,int poolSize) {
        ExecutorService executorService = executors.get(poolName);//从任务池中根据任务名称获取任务信息
        if (null == executorService) {//如果没有获取到
            synchronized (TaskProcessUtil.class) {//加锁
                /**
                 * 在外面获取可能会因为并发执行另一个线程也刚好执行到这一步,两个线程都认为executorService为空,然后进行创建线程池
                 * 但是在synchronized里执行就可以保证同一个时间只有一个线程在执行synchronized里的代码
                 * 线程A和线程B同时执行到外层if并进入争夺synchronized的阶段,假设线程A获取到锁进入synchronized代码块,线程B就会暂时挂起
                 * 线程A进入后再次获取任务对象并进行判断,若为空则创建线程池,并将线程池放入任务队列中
                 * 线程A执行完毕释放锁
                 * 线程B获得锁
                 * 线程B再次获取executorService,这次会获取到线程A创建的executorService
                 * 然后线程B执行完代码,释放锁
                 */
                executorService = executors.get(poolName);//再次获取任务信息
                if (null == executorService) {
                    executorService = init(poolName, poolSize);
                    executors.put(poolName, executorService);
                }
            }
        }
        return executorService;//返回一个线程池对象
    }

    // 回收线程资源
    public static void releaseExecutors(String poolName) {
        ExecutorService executorService = executors.remove(poolName);//map的remove()方法会将移除的值返回来
        if (executorService != null) {//如果移除的任务对应的线程池不为空
            executorService.shutdown();//shutdown()：停止接收新任务，原来的任务继续执行
        }
    }
}
